package top.idetect.client.modules.cloth.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import top.idetect.client.modules.cloth.model.DynamicConfig;
import top.idetect.client.modules.cloth.model.Flaw;
import top.idetect.client.modules.cloth.mapper.FlawMapper;
import top.idetect.client.modules.cloth.service.DynamicConfigService;
import top.idetect.client.modules.cloth.service.FlawService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author wjh
 * @since 2024-03-15
 */
@Slf4j
@Service
public class FlawServiceImpl extends ServiceImpl<FlawMapper, Flaw> implements FlawService {

    @Autowired
    private DynamicConfigService dynamicConfigService;

//    ExecutorService executorService = Executors.newCachedThreadPool();

    public static Map<String, List<Map>> flawStatisticCache = new HashMap<>();

    @Override
    public Page<Flaw> page(Integer pageSize, Integer pageNum, String keywords, String clothSerial, String classStr, String orderBy, Double realLen, Double realArea) {
        Page<Flaw> page = new Page(pageNum, pageSize);
        QueryWrapper<Flaw> wrapper = new QueryWrapper<>();
        wrapper.select(Flaw.class, tableFieldInfo -> !tableFieldInfo.getColumn().equals("img_data"));
        LambdaQueryWrapper<Flaw> lambda = wrapper.lambda();
        if(StrUtil.isNotEmpty(clothSerial)) {
            lambda.eq(Flaw::getClothSerial, clothSerial);
        }
        if(StrUtil.isNotEmpty(classStr)) {
            lambda.eq(Flaw::getClassStr, classStr);
        }
        if(realLen != null){
            lambda.ge(Flaw::getRealLen, realLen);
        }
        if(realArea != null){
            lambda.ge(Flaw::getRealArea, realArea);
        }
        if(StrUtil.isNotEmpty(orderBy)) {
            lambda.orderByDesc(Flaw::getRealArea).orderByDesc(Flaw::getRealLen);
        }
        Page<Flaw> page1 = page(page, wrapper);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        boolean flag = true;
        List<Flaw> records = page1.getRecords();
        for(Flaw flaw : records){
            if(StrUtil.isEmpty(flaw.getImgDataThumbnail())){
                flag = false;
                break;
            }
            // 时间戳处理   5_1715940739
            if(flaw.getTimestampNew() != null){
                Long timeLong = Long.parseLong(flaw.getTimestampNew().substring(2, 12));
                LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(timeLong*1000), ZoneOffset.of("+8"));
                flaw.setTimestamp(localDateTime);
            }
        }
        if(flag){
            return page1;
        }else{
            // 接口实时对无缩略图的数据进行resize
            QueryWrapper<Flaw> wrapper1 = new QueryWrapper<>();
            LambdaQueryWrapper<Flaw> lambda1 = wrapper1.lambda();
            if(StrUtil.isNotEmpty(clothSerial)) {
                lambda1.eq(Flaw::getClothSerial, clothSerial);
            }
            if(StrUtil.isNotEmpty(classStr)) {
                lambda1.eq(Flaw::getClassStr, classStr);
            }

            if(realLen != null){
                lambda.ge(Flaw::getRealLen, realLen);
            }
            if(realArea != null){
                lambda.ge(Flaw::getRealArea, realArea);
            }
            if(StrUtil.isNotEmpty(orderBy)) {
                lambda1.orderByDesc(Flaw::getRealArea).orderByDesc(Flaw::getRealLen);
            }
            ArrayList<Flaw> tempList = new ArrayList<>();
            Page<Flaw> page2 = page(page, wrapper1);
            for(Flaw tempFlaw : page2.getRecords()){
                if(StrUtil.isEmpty(tempFlaw.getImgDataThumbnail())){

                    Flaw updateFlaw = new Flaw();
                    updateFlaw.setId(tempFlaw.getId());

                    if(!tempFlaw.getImgData().startsWith("/9j/")){
                        tempFlaw.setImgDataThumbnail("error");
                        updateFlaw.setImgDataThumbnail("error");
                        tempList.add(updateFlaw);
                        continue;
                    }
                    // 将 base64 编码的图片数据解码为字节数组
                    byte[] imageData = Base64.getDecoder().decode(tempFlaw.getImgData());

                    // 加载图片
                    BufferedImage inputImage = null;
                    try {
                        inputImage = ImageIO.read(new ByteArrayInputStream(imageData));
                        // 获取图片宽度和高度
                    } catch (IOException e) {
                        log.info("Error: " + e.getMessage());
                    }

                    // 缩放后的宽度和高度
                    int scaledWidth = 40;
                    int scaledHeight = 40;

                    // 创建一个 BufferedImage 对象来存储缩放后的图片
                    BufferedImage outputImage = new BufferedImage(scaledWidth, scaledHeight, inputImage.getType());

                    // 使用 Graphics2D 对象绘制缩放后的图片
                    Graphics2D g2d = outputImage.createGraphics();
                    g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);
                    g2d.dispose();

                    // 将缩放后的图片转换为 base64 编码的字符串
                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                    try {
                        ImageIO.write(outputImage, "png", outputStream);
                    } catch (IOException e) {
                        log.info("Error: " + e.getMessage());
                    }
                    String resizedBase64ImageData = Base64.getEncoder().encodeToString(outputStream.toByteArray());

                    tempFlaw.setImgDataThumbnail(resizedBase64ImageData);

                    updateFlaw.setImgDataThumbnail(resizedBase64ImageData);
                    tempList.add(updateFlaw);
                }
                tempFlaw.setImgData(null);
            }
            updateBatchById(tempList);
            return page2;
        }

    }

    @Override
    public Page<Flaw> pageNoImg(Integer pageSize, Integer pageNum, String clothSerial, String classStr) {
        Page<Flaw> page = new Page(pageNum, pageSize);
        QueryWrapper<Flaw> wrapper = new QueryWrapper<>();
        wrapper.select(Flaw.class, tableFieldInfo ->
                !tableFieldInfo.getColumn().equals("img_data") &&
                        !tableFieldInfo.getColumn().equals("img_data_thumbnail") &&
                        !tableFieldInfo.getColumn().equals("cloth_serial") &&
                        !tableFieldInfo.getColumn().equals("camera_id") &&
                        !tableFieldInfo.getColumn().equals("pnt"));

        LambdaQueryWrapper<Flaw> lambda = wrapper.lambda();
        if(StrUtil.isNotEmpty(clothSerial)) {
            lambda.eq(Flaw::getClothSerial, clothSerial);
        }
        if(StrUtil.isNotEmpty(classStr)) {
            lambda.eq(Flaw::getClassStr, classStr);
        }
        return page(page, wrapper);
    }

    @Override
    public List<Map> statistic(String clothSerial) throws ExecutionException, InterruptedException {
        if(flawStatisticCache.containsKey(clothSerial)){
            return flawStatisticCache.get(clothSerial);
        }
        List<Map> mapList = new ArrayList<>();
        DynamicConfig class_str_v1 = dynamicConfigService.getByConfigName("flaw_class_str_v2");
        mapList.add(getMap(baseMapper.statisticChannel1(clothSerial),"通道一",class_str_v1.getConfigValue()));
        mapList.add(getMap(baseMapper.statisticChannel2(clothSerial),"通道二",class_str_v1.getConfigValue()));
        mapList.add(getMap(baseMapper.statisticChannel3(clothSerial),"通道三",class_str_v1.getConfigValue()));
        mapList.add(getMap(baseMapper.statistic(clothSerial),"合计",class_str_v1.getConfigValue()));

        // 异步获取三个通道的统计数据
//        CompletableFuture<HashMap<String, Object>> listCompletableFuture = CompletableFuture.supplyAsync(() -> getMap(baseMapper.statistic(clothSerial), "合计", class_str_v1.getConfigValue()), executorService);
//        CompletableFuture<HashMap<String, Object>> listCompletableFuture1 = CompletableFuture.supplyAsync(() -> getMap(baseMapper.statisticChannel1(clothSerial), "通道一", class_str_v1.getConfigValue()), executorService);
//        CompletableFuture<HashMap<String, Object>> listCompletableFuture2 = CompletableFuture.supplyAsync(() -> getMap(baseMapper.statisticChannel2(clothSerial), "通道二", class_str_v1.getConfigValue()), executorService);
//        CompletableFuture<HashMap<String, Object>> listCompletableFuture3 = CompletableFuture.supplyAsync(() -> getMap(baseMapper.statisticChannel3(clothSerial), "通道三", class_str_v1.getConfigValue()), executorService);
//        mapList.add(listCompletableFuture1.get());
//        mapList.add(listCompletableFuture2.get());
//        mapList.add(listCompletableFuture3.get());
//        mapList.add(listCompletableFuture.get());

        flawStatisticCache.put(clothSerial, mapList);
        return flawStatisticCache.get(clothSerial);

//        return mapList;
    }

    public static HashMap<String, Object> getMapOld(List<Map> statisticChannel,String channel){
        HashMap<String, Object> map = new HashMap<>();
        map.put("分区",channel);
        map.put("划痕", 0);
        map.put("污损", 0);
        map.put("线状", 0);
        map.put("针孔", 0);
        map.put("其他", 0);
        map.put("合计", 0);
        if(!statisticChannel.isEmpty()){
            Integer count = 0;
            for (Map temp : statisticChannel) {
                count += Integer.parseInt(temp.get("classCount").toString());
                map.put(temp.get("classStr").toString(),Integer.parseInt(temp.get("classCount").toString()));
            }
            map.put("合计", count);
        }
        return map;
    }

    public static HashMap<String, Object> getMap(List<Map> statisticChannel,String channel,String class_str_v1){
        String[] split = class_str_v1.split(",");

        HashMap<String, Object> map = new HashMap<>();
        map.put("分区",channel);
        for(int i = 0; i < split.length; i++){
            map.put(split[i], 0);
        }
//        map.put("合计", 0);
        if(!statisticChannel.isEmpty()){
            Integer count = 0;
            for (Map temp : statisticChannel) {
                if(class_str_v1.contains(temp.get("classStr").toString())){
                    count += Integer.parseInt(temp.get("classCount").toString());
                    map.put(temp.get("classStr").toString(),Integer.parseInt(temp.get("classCount").toString()));
                }else{
                    map.remove(temp.get("classStr").toString());
                }
            }
            map.put("合计", count);
        }
        return map;
    }
    @Override
    public List<Flaw> listNoImg(String clothSerial, String classStr) {
        QueryWrapper<Flaw> wrapper = new QueryWrapper<>();
        wrapper.select(Flaw.class, tableFieldInfo ->
                                !tableFieldInfo.getColumn().equals("img_data") &&
                                !tableFieldInfo.getColumn().equals("img_data_thumbnail") &&
                                !tableFieldInfo.getColumn().equals("cloth_serial") &&
                                !tableFieldInfo.getColumn().equals("camera_id") &&
                                !tableFieldInfo.getColumn().equals("real_len") &&
                                !tableFieldInfo.getColumn().equals("real_area") &&
                                !tableFieldInfo.getColumn().equals("pnt"));

        LambdaQueryWrapper<Flaw> lambda = wrapper.lambda();
        if(StrUtil.isNotEmpty(clothSerial)) {
            lambda.eq(Flaw::getClothSerial, clothSerial);
        }
        if(StrUtil.isNotEmpty(classStr)) {
            lambda.eq(Flaw::getClassStr, classStr);
        }
//        long beginTime = System.currentTimeMillis();
        List<Flaw> flaws = baseMapper.selectList(wrapper);
//        long endTime = System.currentTimeMillis();
//        log.info("列表查询耗时: begin:{} -- end:{} -- 时长:{}",beginTime, endTime, endTime - beginTime);

        return flaws;
    }

    @Override
    public List<Flaw> listExcel(String clothSerial, String classStr) {
        QueryWrapper<Flaw> wrapper = new QueryWrapper<>();
        wrapper.select(Flaw.class, tableFieldInfo ->
                        !tableFieldInfo.getColumn().equals("img_data") &&
                        !tableFieldInfo.getColumn().equals("img_data_thumbnail"));

        LambdaQueryWrapper<Flaw> lambda = wrapper.lambda();
        if(StrUtil.isNotEmpty(clothSerial)) {
            lambda.eq(Flaw::getClothSerial, clothSerial);
        }
        if(StrUtil.isNotEmpty(classStr)) {
            lambda.eq(Flaw::getClassStr, classStr);
        }
        return baseMapper.selectList(wrapper);
    }

    @Override
    public List<Flaw> listImgNoNail() {
        QueryWrapper<Flaw> wrapper = new QueryWrapper<>();
        wrapper.select("id,img_data");
        LambdaQueryWrapper<Flaw> lambda = wrapper.lambda();
        lambda.isNull(Flaw::getImgDataThumbnail);
        lambda.last("limit 500");
        return baseMapper.selectList(wrapper);
    }
}
